package com.zbkj.crmeb.block.agent;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.common.MyRecord;
import com.constants.Constants;
import com.exception.CrmebException;
import com.zbkj.crmeb.block.HttpUtil;
import com.zbkj.crmeb.block.vo.BlockAccount;
import com.zbkj.crmeb.block.vo.BlockBalance;
import com.zbkj.crmeb.block.vo.BlockResponse;
import com.zbkj.crmeb.front.response.StoreProductTraceResponse;
import com.zbkj.crmeb.system.service.SystemConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class BlockAgent {
    private static String BARE_TOKEN = "";

    public static void cleanToken() {
        BARE_TOKEN = "";
    }


    public static TypeReference TYPE_STRING = new TypeReference<BlockResponse.ResponseToken>() {
    };

    public static TypeReference TYPE_BLOCK_ACCOUNT = new TypeReference<BlockResponse.Response<BlockAccount>>() {
    };

    public static TypeReference TYPE_BLOCK_BALANCES = new TypeReference<BlockResponse.Response<List<BlockBalance>>>() {
    };

    public static TypeReference TYPE_TRANSACTION_RESULT = new TypeReference<BlockResponse.Response<String>>() {
    };

    public static TypeReference TYPE_BLOCK_TRACE_LIST = new TypeReference<BlockResponse.Response<List<StoreProductTraceResponse>>>() {
    };

    public static TypeReference TYPE_RESPONSE = new TypeReference<BlockResponse.Response<Object>>() {
    };

    @Autowired
    private SystemConfigService systemConfigService;

    private String getApiUrl() {
        String apiUrl = systemConfigService.getValueByKey(Constants.CONFIG_KEY_TOKEN_SERVER_URL);
        if (StringUtils.isEmpty(apiUrl)) throw new CrmebException("链积分api地址未配置");
        return apiUrl;
    }

    private String getUserName() {
        String userName = systemConfigService.getValueByKey(Constants.CONFIG_KEY_TOKEN_SERVER_USERNAME);
        if (StringUtils.isEmpty(userName)) throw new CrmebException("链积分用户名不存在");
        return userName;
    }

    private String getPass() {
        String passowd = systemConfigService.getValueByKey(Constants.CONFIG_KEY_TOKEN_SERVER_PASSWORD);
        if (StringUtils.isEmpty(passowd)) throw new CrmebException("链积分密码不存在");
        return passowd;
    }

    public BlockResponse.ResponseToken getToken() throws IOException {
        try {
            String result = HttpUtil.doPost(getApiUrl() + Path.PATH_LOGIN, null, null, new HashMap<String, Object>() {{
                put("username", getUserName());
                put("password", getPass());
            }}, null, true);

            BlockResponse.ResponseToken response = JSONObject.parseObject(result, TYPE_STRING.getType());
            return response;
        } catch (Exception e) {
            cleanToken();
            throw e;
        }
    }


    public BlockResponse.Response<BlockAccount> createTokeAddress(String phone) {
        try {
            log.info("[Block Agent] METHOD: [{}] PARAMS 电话号码: [{}]", "添加链账户地址", phone);
            String result = HttpUtil.doPost(getApiUrl() + Path.PATH_ACCOUNT, null, null,
                    new HashMap<String, Object>() {{
                        put("accountId", phone);
                    }}, authorization(), true);
            return JSONObject.parseObject(result, TYPE_BLOCK_ACCOUNT.getType());
        } catch (Exception e) {
            handleException(e);
            e.printStackTrace();
            throw new CrmebException("链服务异常，请联系管理员");
        }
    }

    public BlockResponse.Response<String> genTransaction(BlockTransaction transaction) {
        try {
            log.info("[Block Agent] METHOD: [{}] PARAMS 交易信息: [{}]", "添加交易", JSON.toJSONString(transaction));
            String result = HttpUtil.doPostJson(getApiUrl() + Path.PATH_TRANSACTION_CREATE, null, null,
                    JSON.toJSONString(transaction), authorization(), true);
            return JSONObject.parseObject(result, TYPE_TRANSACTION_RESULT.getType());
        } catch (Exception e) {
            handleException(e);
            e.printStackTrace();
            throw new CrmebException("链服务异常，请联系管理员");
        }
    }

    public BlockResponse.Response<BlockAccount> getTokenInfo(String phone) {
        try {
            log.info("[Block Agent] METHOD: [{}] PARAMS 电话号码: [{}]", "添加链账户地址", phone);
            String result = HttpUtil.doGet(getApiUrl() + Path.PATH_ACCOUNT_INFO, null,
                    new HashMap<String, Object>() {{
                        put("accountId", phone);
                    }}, authorization());
            return JSONObject.parseObject(result, TYPE_BLOCK_ACCOUNT.getType());
        } catch (Exception e) {
            handleException(e);
            e.printStackTrace();
            throw new CrmebException("链服务异常，请联系管理员");
        }
    }

    public BlockResponse.Response<List<BlockBalance>> getBalance(String address, String contractName) {
        String result = null;
        try {
            result = HttpUtil.doGet(getApiUrl() + Path.PATH_BALANCE + "/" + address + "/info", null,
                    new HashMap<String, Object>() {{
                        put("contractName", contractName);
                    }}, authorization());
        } catch (Exception e) {
            handleException(e);
            e.printStackTrace();
            throw new CrmebException("链服务异常，请联系管理员");
        }
        return JSONObject.parseObject(result, TYPE_BLOCK_BALANCES.getType());
    }


    public BlockResponse.Response<List<StoreProductTraceResponse>> getTraceInfo(String hash) {
        String result = null;
        try {
            result = HttpUtil.doGet(getApiUrl() + Path.PATH_TRACE + "?hash="+hash, null,null, authorization());
        } catch (Exception e) {
            handleException(e);
            e.printStackTrace();
            throw new CrmebException("链服务异常，请联系管理员");
        }
        return JSONObject.parseObject(result, TYPE_BLOCK_TRACE_LIST.getType());
    }

    public void handleException(Exception e)  {
        if(e instanceof CrmebException){
            if(((  CrmebException)e).getMessage().contains("认证失败")){
                cleanToken();
                throw (  CrmebException)e;
            }
        }
    }


    public void login() {
        try {
            BlockResponse.ResponseToken response = getToken();
            if (!StringUtils.isEmpty(response.getToken())) {
                BARE_TOKEN = response.getToken();
            } else {
                log.warn("can not extract expire_token from login response body, may be face server crashed !!");
                throw new CrmebException("区块链服务不可用");
            }
        } catch (Exception e) {
            e.printStackTrace();
            BARE_TOKEN = "";
        }
    }

    public Map<String, Object> authorization() {
        if (StringUtils.isEmpty(BARE_TOKEN)) {
            login();
        }
        return new HashMap<String, Object>() {{
            put("Authorization", BARE_TOKEN);
        }};
    }


}
